//
//  BackgroundTaskManager.swift
//  hku3
//
//  Created by wsg on 2017/7/5.
//  Copyright © 2017年 wsg. All rights reserved.
//

import Foundation
import UIKit

public typealias void_block_t = () -> Void
let kSessionID = "com.backgroundtaskmanager"
let kDownloadSource = "https://v2.photokharma.io/heartbeat"
class BackgroundTaskManager: NSObject, URLSessionDelegate,URLSessionTaskDelegate {
    private var count: Int = 0
    private var bgTaskId = UIBackgroundTaskIdentifier.invalid
    lazy private var downloadRequest: URLRequest = {
        return URLRequest(url: URL(string: kDownloadSource)!)
    }()
    private var completionHandler:void_block_t?
    class func beginBackgroundTask(withLocalCounter localCounter: Int) {
//        localCounter += 1
        self.shared.beginBackgroundTask()
    }
    
    class func endBackgroundTask(withLocalCounter localCounter: Int) {
        assert(localCounter != 0, "Local count must be > 0.")
//        localCounter -= 1
        self.shared.endBackgroundTask()
    }
    
    
    static let shared : BackgroundTaskManager = {
        return BackgroundTaskManager()
    }()
    
    class func beginBackgroundTask() {
        BackgroundTaskManager.shared.beginBackgroundTask()
    }
    
    class func endBackgroundTask() {
        BackgroundTaskManager.shared.endBackgroundTask()
    }
    
    
    func cancelBackgroundTask() {
        if bgTaskId != UIBackgroundTaskIdentifier.invalid {
            UIApplication.shared.endBackgroundTask(bgTaskId)
            bgTaskId = UIBackgroundTaskIdentifier.invalid
        }
    }
    
    func createBackgroundTask() {
        bgTaskId = UIApplication.shared.beginBackgroundTask(expirationHandler: {
            //start URLSession
            self.startURLSession()
            //cancel Background Task
            self.cancelBackgroundTask()
        })
    }
    
    func beginBackgroundTask() {
        assert(Thread.isMainThread, "Must be called from main thread.")
        if count == 0 {
            createBackgroundTask()
        }
        count += 1
    }
    
    func endBackgroundTask() {
        assert(Thread.isMainThread, "Must be called from main thread.")
        assert(count != 0, "Count must be > 0.")
        count -= 1
        if count == 0 {
            cancelBackgroundTask()
        }
    }
    
    lazy var backgroundURLSession : URLSession = {
        let sessionConfig: URLSessionConfiguration = URLSessionConfiguration.background(withIdentifier: kSessionID)
        sessionConfig.timeoutIntervalForRequest = 2.0
        sessionConfig.timeoutIntervalForResource = 2.0
        
        return URLSession(configuration: sessionConfig, delegate: self as URLSessionDelegate, delegateQueue: OperationQueue.main)
    }()
    
    class func handleEvents(forBackgroundURLSession identifier: String, completionHandler: @escaping void_block_t) -> Bool {
        return BackgroundTaskManager.shared.vhandleEvents(forBackgroundURLSession: identifier, completionHandler: completionHandler)
    }

    func startURLSession() {
        self.backgroundURLSession.downloadTask(with: downloadRequest).resume()
    }

    public func vhandleEvents(forBackgroundURLSession identifier: String, completionHandler: @escaping void_block_t) -> Bool {
        // A reference to the background session must be re-established
        // or NSURLSessionDownloadDelegate and NSURLSessionDelegate methods will not be called
        // as no delegate is attached to the session. See backgroundURLSession above.
        _ = self.backgroundURLSession
        if (identifier == kSessionID) {
            self.completionHandler = completionHandler
            return true
        }
        return false
    }

    // MARK: - NSURLSession Delegate method implementation
    func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
        // Check if all download tasks have been finished.
        self.backgroundURLSession.getTasksWithCompletionHandler { (dataTasks, uploadTasks, downloadTasks) in
            if downloadTasks.count == 0 {
                //calling completion handler
                if self.completionHandler != nil {
                    self.completionHandler!()
                    self.completionHandler = nil
                }
            }
        }
    }

    public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        //create background task regardless if task completed with error or not
        createBackgroundTask()
    }
}
